package org.KeyCrafter.key;

import org.KeyCrafter.cmd.ListCommand;
import org.KeyCrafter.obj.ListObj;
import org.KeyCrafter.obj.KeyCrafterObjFactory;
import org.KeyCrafter.obj.KeyCrafterObject;
import org.KeyCrafter.obj.type.ListType;
import org.KeyCrafter.server.session.ClientSession;
import org.KeyCrafter.util.SharedReply;

import static org.KeyCrafter.obj.KeyCrafterObject.KeyCrafter_LIST;
import static org.KeyCrafter.obj.type.ListType.KeyCrafter_HEAD;
import static org.KeyCrafter.obj.type.ListType.KeyCrafter_TAIL;
import static org.KeyCrafter.util.ReplyUtil.*;

public class ListKey implements ListCommand {
    @Override
    public void lpushCommand(ClientSession c) {
        pushGenericCommand(c,KeyCrafter_HEAD);
    }

    private void pushGenericCommand(ClientSession c, int where) {
        // 取出列表对象
        KeyCrafterObject lobj = c.db().lookupKeyWrite(c.argv(1));
        if (lobj != null && !(lobj instanceof ListObj)){
            addReply(c, SharedReply.wrongTypeErr);
            return;
        }
        // 将列表状态设置为就绪
//        if (mayHaveWaitingClients) {
//            signalListAsReady(c,c.argv(1));
//        }
        // 如果列表对象不存在，那么创建一个，并关联到数据库
        if (lobj == null) {
            lobj = KeyCrafterObjFactory.newListObj();
            c.db().dbAdd(c.argv(1),lobj);
        }
        // 遍历所有输入值，并将它们添加到列表中
        int pushed = 0;
        ListType listType = ((ListObj) lobj).getValue();
        for (int j = 2; j < c.argc(); j++) {
            // 编码，采用原始的 Java String
            // 将值推入到列表
            listType.push(c.argv(j), where);
            pushed++;
        }
        // 返回添加的节点数量
        addReplyLong(c,listType.length());

        // 修改数据库
        c.db().addDirty(pushed);
    }

    @Override
    public void lpopCommand(ClientSession c) {
        popGenericCommand(c, KeyCrafter_HEAD);
    }

    private void popGenericCommand(ClientSession c, int where) {
        // 取出列表对象
        KeyCrafterObject o = c.db().lookupKeyReadOrReply(c, c.argv(1), SharedReply.nullBulk);
        if (o == null || !checkType(c,o,KeyCrafter_LIST)) {
            return;
        }

        ListType listType = ((ListObj) o).getValue();
        // 弹出列表元素
        Object value = listType.pop(where);
        // 根据弹出元素是否为空，决定后续动作
        if (value == null) {
            addReply(c,SharedReply.nullBulk);
        } else {
            // 回复弹出的数据
            addReplyBulk(c,value.toString());
            // 当列表的长度为 0 是，删除这个键
            if (listType.length() == 0) {
                c.db().delete(c.argv(1));
            }
            // 修改了数据库
            c.db().incrDirty();
        }
    }

    @Override
    public void llenCommand(ClientSession c) {
        KeyCrafterObject o = c.db().lookupKeyReadOrReply(c, c.argv(1), SharedReply.cZero);
        if (o == null || !checkType(c, o, KeyCrafter_LIST)) return;
        ListType listType = (ListType) o.getValue();
        addReplyLong(c, listType.length());
    }

    @Override
    public void rpushCommand(ClientSession c) {
        pushGenericCommand(c, KeyCrafter_TAIL);
    }

    @Override
    public void lrangeCommand(ClientSession c) {
        // 取出索引值 start 和 end
        long start, end;
        try {
            start =  Long.parseLong(c.argv(2));
            end = Long.parseLong(c.argv(3));
        } catch (NumberFormatException e){
            addReplyError(c, "value is not an integer or out of range");
            return;
        }
        // 取出列表名单
        KeyCrafterObject o;
        if ((o = c.db().lookupKeyReadOrReply(c, c.argv(1), SharedReply.emptyMultiBulk)) == null
                || !checkType(c, o, KeyCrafter_LIST)){
            return;
        }
        ListType listType = ((ListObj) o).getValue();
        // 取出列表长度
        long llen = listType.length();
        // 将负数索引转换成正数索引
        if (start < 0) {
            start = llen + start;
        }
        if (end < 0) {
            end = llen + end;
        }
        if (start < 0) {
            start = 0;
        }
        if (start > end || start >= llen) {
            addReply(c, SharedReply.emptyMultiBulk);
            return;
        }
        if (end >= llen) {
            end = llen - 1;
        }
        long rangeLen = (end - start) + 1;
        // 回复数组
        String[] reply = new String[(int) rangeLen];
        listType.range(start, rangeLen, reply);
        addReplyArray(c, reply);
    }
}
